package main

import (
	"encoding/json"
	"fmt"
	"log"
	"math/rand"
	"net/http"
	"net/http/httputil"
	"net/url"
	"os"
	"time"
)

// ProxyServer 表示一个后端服务器的地址配置
type ProxyServer struct {
	Addr string `json:"addr"`
}

// ProxyConfig 表示整个反向代理的配置
type ProxyConfig struct {
	Servers   []ProxyServer `json:"servers"`
	Strategy  string        `json:"strategy"`
	ProxyPort int64         `json:"proxyPort"`
}

// GatewayHandler 实现了反向代理和负载均衡逻辑
type GatewayHandler struct {
	ProxyConfig ProxyConfig
	Servers     []*url.URL
	Index       int
}

// ChooseServer 决定应该将请求转发到哪个后端服务器上
func (h *GatewayHandler) ChooseServer(r *http.Request) *url.URL {
	if len(h.ProxyConfig.Servers) == 0 {
		return nil
	}

	switch h.ProxyConfig.Strategy {
	case "ip_hash":
		ip := r.RemoteAddr // 获取请求的客户端IP
		hash := fnvHash(ip) % len(h.ProxyConfig.Servers)
		return h.Servers[hash]
	case "random":
		rand.Seed(time.Now().UnixNano())
		index := rand.Intn(len(h.ProxyConfig.Servers))
		return h.Servers[index]
	default: // 默认使用轮询策略
		server := h.Servers[h.Index]
		h.Index = (h.Index + 1) % len(h.ProxyConfig.Servers)
		return server
	}
}

// ServeHTTP 代理请求到后端服务器
func (h *GatewayHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	serverURL := h.ChooseServer(r)
	if serverURL == nil {
		http.Error(w, "No available backend server", http.StatusServiceUnavailable)
		return
	}

	proxy := httputil.NewSingleHostReverseProxy(serverURL)
	proxy.ServeHTTP(w, r)
}

func main() {
	Proxy()
}

func Proxy() {
	configData, err := os.ReadFile("./config.json")
	if err != nil {
		log.Fatal("Failed to read config file:", err)
	}

	var proxyConfig ProxyConfig
	err = json.Unmarshal(configData, &proxyConfig)
	if err != nil {
		log.Fatal("Failed to parse config file:", err)
	}

	handler := &GatewayHandler{
		ProxyConfig: proxyConfig,
		Servers:     make([]*url.URL, len(proxyConfig.Servers)),
	}

	for i, server := range proxyConfig.Servers {
		serverURL := &url.URL{Scheme: "http", Host: server.Addr}
		handler.Servers[i] = serverURL
	}

	if proxyConfig.ProxyPort == 0 {
		proxyConfig.ProxyPort = 8088
	}
	log.Println(fmt.Sprintf("Starting gateway server on port %d...", proxyConfig.ProxyPort))
	err = http.ListenAndServe(fmt.Sprintf(":%d", proxyConfig.ProxyPort), handler)
	if err != nil {
		log.Fatal("Gateway server stopped:", err)
	}
}

// 哈希函数，用于IP哈希策略
func fnvHash(str string) int {
	hash := 2166136261

	for _, c := range str {
		hash ^= int(c)
		hash *= 16777619
	}

	return hash
}
